package gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import mines.MineType;
import mines.Pointer;
import mines.Real;

public class Window extends JFrame {

	private final String TITLE = "Minesweeper!";
	private final String MINES_LEFT = "Mines left: ";
	private final String RESTART = "New";
	private final String QUIT = "Exit";
	
	private final int MINESIZE = 25;
	private final int MINE_PERCENT = 60;
	
	private int minesWidth = 250;
	private int minesHeight = 250;

	private HashMap<Point, MineType> mines;

	private JPanel jMain = null;
	private JPanel jMines = null;
	private JPanel jBottom = null;
	private JPanel jButtons = null;
	
	private JButton jQuit = null;
	private JButton jRestart = null;
	
	private JLabel minesLeft = null;
	
	private GridBagConstraints gbc = null;
	private int left = 0;

	public Window() {
		setup();
		generateMap();
		addItems();
	}

	private void setup() {
		this.setVisible(true);
		this.setTitle(TITLE);
		this.setContentPane(getMain());
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setResizable(false);
	}

	private JPanel getMain() {
		if (jMain == null) {
			jMain = new JPanel(true);
			jMain.setLayout(new BorderLayout());
		}
		return jMain;
	}

	private JPanel getMines() {
		if (jMines == null) {
			jMines = new JPanel();
			jMines.setLayout(new GridBagLayout());
			gbc = new GridBagConstraints();
			gbc.fill = GridBagConstraints.BOTH;
			gbc.insets = new Insets(1, 1, 1, 1);
			jMines.setPreferredSize(new Dimension(minesWidth, minesHeight));
		}
		return jMines;
	}

	private void generateMap() {
		mines = new HashMap<Point, MineType>();
		Random random = new Random();

		int height = (int) getMines().getPreferredSize().getHeight();
		int width = (int) getMines().getPreferredSize().getWidth();

		int minesTotal = Math.round((height * width)
				/ ((MINESIZE + 4) * (MINESIZE + 4)));
		int minesReal = (int) Math.round((double) minesTotal
				* ((double) MINE_PERCENT / 100));
		int minesPerRow = Math.round(width / (MINESIZE + 2));
		int rows = minesTotal / minesPerRow;
		
		left = minesReal;

		for (int y = 0; y <= rows; y++) {
			for (int x = 0; x < minesPerRow; x++) {
				Point tmpPoint = new Point(x, y);
				MineType mt;

				if (minesReal > 0 && random.nextBoolean()) {
					mt = new Real(this);
					minesReal--;
				} else {
					mt = new Pointer(this);
				}
				gbc.gridx = x;
				gbc.gridy = y;
				getMines().add(mt, gbc);
				mines.put(tmpPoint, mt);
			}
		}
		setFlags();
	}

	private void setFlags() {
		Iterator<Point> it = mines.keySet().iterator();
		while (it.hasNext()) {
			Point p = it.next();
			MineType mt = mines.get(p);
			if (mt instanceof Pointer) {
				int y = (int) p.getY();
				int x = (int) p.getX();
				int nr = 0;
				for (int yy = y - 1; yy <= y + 1; yy++) {
					for (int xx = x - 1; xx <= x + 1; xx++) {
						MineType tmpMine = mines.get(new Point(xx, yy));
						if (tmpMine instanceof Real) {
							nr++;
						}
					}
				}
				((Pointer) mt).setNr(nr);
			}
		}
	}
	private JPanel getBottom() {
		if (jBottom == null) {
			jBottom = new JPanel();
			jBottom.setLayout(new BorderLayout());
			jBottom.add(getMinesLeft(), BorderLayout.WEST);
			jBottom.add(getButtons(), BorderLayout.EAST);
		}
		return jBottom;
	}
	
	public JLabel getMinesLeft() {
		if (minesLeft == null) {
			minesLeft = new JLabel(MINES_LEFT + left);
		}
		return minesLeft;
	}
	
	public JPanel getButtons() {
		if (jButtons == null) {
			jButtons = new JPanel();
			jButtons.setLayout(new FlowLayout());
			jButtons.add(getRestart());
			jButtons.add(getQuit());
		}
		return jButtons;
	}
	
	private JButton getRestart() {
		if (jRestart == null) {
			jRestart = new JButton(RESTART);
			jRestart.setPreferredSize(new Dimension(80,30));
			jRestart.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent arg0) {
					getMines().removeAll();
					generateMap();
					addItems();
				}
			});
		}
		return jRestart;
	}
	
	private JButton getQuit() {
		if (jQuit == null) {
			jQuit = new JButton(QUIT);
			jQuit.setPreferredSize(new Dimension(60,30));
			jQuit.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent arg0) {
					System.exit(0);				
				}
			});
		}
		return jQuit;
	}
	
	private void addItems() {
		getMain().add(getMines(), BorderLayout.CENTER);
		getMain().add(getBottom(), BorderLayout.SOUTH);
		setText();
		this.pack();
		this.validate();
	}
	
	private void setText() {
		getMinesLeft().setText(MINES_LEFT + left);
	}
	
	public void decreaseMines() {
		left--;
		if (left <= 0) {
			System.out.println("Game over!");
		}
		setText();
	}
	
	public void gameOver() {
		Iterator<Point> it = mines.keySet().iterator();
		while (it.hasNext()) {
			Point p = it.next();
			MineType mt = mines.get(p);
			mt.reveal();
		}
	}
}
